﻿namespace BM.Tools.WebControls.MForm.Controls.Helper
{
    using System;
    using System.Globalization;
    using System.Xml.Schema;

    using Items;

    /// <summary>
    /// This class performs to and from xml value formattings.
    /// </summary>
    internal class LeafItemValueFormatter
    {
        public LeafItemValueFormatter(LeafItem item)
        {
            Item = item;
        }

        public LeafItem Item
        {
            get;
            private set;            
        }

        public static string GetXmlValue(LeafItem item)
        {
            var formatter = new LeafItemValueFormatter(item);
            return formatter.GetXmlValue(item.DataTypeValue);
        }

        public static void SetXmlValue(LeafItem item, string xmlValue)
        {
            var formatter = new LeafItemValueFormatter(item);
            item.DataTypeValue = formatter.GetUserValue(xmlValue);
        }

        public string GetXmlValue(string userValue)
        {
            return FormatValue(userValue, ConvertUserDecimalToXml, ConvertUserDateTimeToXml);            
        }

        public string GetUserValue(string xmlValue)
        {
            return FormatValue(xmlValue, ConvertXmlDecimalToUser, ConvertXmlDateTimeToUser);
        }

        private string ConvertXmlDecimalToUser(string xmlValue)
        {
            return decimal.Parse(xmlValue, CultureInfo.InvariantCulture).ToString(CultureInfo.CurrentCulture);
        }

        private string ConvertXmlDateTimeToUser(string xmlValue)
        {
            return ConvertXmlDateTime(xmlValue).ToString(Item.Basis.Root.CulturalContext.Formattings[Item.DataType].Format, CultureInfo.CurrentCulture);
        }

        private DateTime ConvertXmlDateTime(string xmlValue)
        {
            try
            {
                return DateTime.ParseExact(xmlValue, GetXmlFormatting(Item.DataType), CultureInfo.InvariantCulture);
            }
            catch (FormatException e)
            {
                return DateTime.Parse(xmlValue, CultureInfo.InvariantCulture);
            }
        }

        private string ConvertUserDecimalToXml(string userValue)
        {
            try
            {
                return decimal.Parse(userValue, CultureInfo.CurrentCulture).ToString(CultureInfo.InvariantCulture);
            } 
            catch (FormatException e)
            {
                return decimal.Parse(userValue, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture);
            }            
        }

        private string ConvertUserDateTimeToXml(string userValue)
        {
            return DateTime.ParseExact(
                                    Item.DataTypeValue,
                                    Item.Basis.Root.CulturalContext.Formattings[Item.DataType].Format,
                                    CultureInfo.CurrentCulture).ToString(GetXmlFormatting(Item.DataType), CultureInfo.InvariantCulture);
        }

        private string FormatValue(string inputValue, Func<string, string> decimalFunc, Func<string, string> dateTimeFunc)
        {
            switch (Item.DataType)
            {                    
                case XmlTypeCode.Decimal:
                case XmlTypeCode.Double:
                case XmlTypeCode.Float:
                case XmlTypeCode.Int:
                case XmlTypeCode.Integer:
                case XmlTypeCode.Long:
                case XmlTypeCode.NegativeInteger:
                case XmlTypeCode.NonNegativeInteger:
                case XmlTypeCode.NonPositiveInteger:
                case XmlTypeCode.PositiveInteger:
                case XmlTypeCode.Short:
                case XmlTypeCode.UnsignedInt:
                case XmlTypeCode.UnsignedLong:
                case XmlTypeCode.UnsignedShort:
                    return decimalFunc(inputValue);                            
                case XmlTypeCode.DateTime:
                case XmlTypeCode.Date:
                case XmlTypeCode.Time:
                case XmlTypeCode.GYearMonth:
                case XmlTypeCode.GMonthDay:
                case XmlTypeCode.GYear:
                case XmlTypeCode.GMonth:
                case XmlTypeCode.GDay:
                    return dateTimeFunc(inputValue);                            
                default:
                    return inputValue;
            }
        }

        private string GetXmlFormatting(XmlTypeCode type)
        {
            switch (type)
            {
                case XmlTypeCode.DateTime:
                    return "yyyy-MM-ddTHH:mm:ss";
                case XmlTypeCode.Date:
                    return "yyyy-MM-dd";
                case XmlTypeCode.Time:
                    return "HH:mm:ss";
                case XmlTypeCode.GYearMonth:
                    return "yyyy-MM";
                case XmlTypeCode.GMonthDay:
                    return "MM-dd";
                case XmlTypeCode.GYear:
                    return "yyyy";
                case XmlTypeCode.GMonth:
                    return "MM";
                case XmlTypeCode.GDay:
                    return "dd";
            }

            return null;
        }
    }
}
